#include "resource.h"

#include <Windows.h>

#include <atlbase.h>
#include <atlcom.h>
#include <atlcoll.h>
#include <atlwin.h>

#include <shlobj.h>
#include <shobjidl.h>
#include <shellapi.h>
#include <shlwapi.h>
#include <shlguid.h>
#include <ntquery.h>
#include <thumbcache.h>

//stl & boost
#include <string>
#include <sstream>

static CLSID MODULE_GUID = { 0x1007d097, 0xddd1, 0x47df, { 0xb4, 0x4, 0x36, 0x14, 0x59, 0xd9, 0xb6, 0x74 } };

class CAtlDllModule : public CAtlDllModuleT<CAtlDllModule>
{ };

CAtlDllModule _AtlModule;

BOOL WINAPI DllMain(
  _In_  HINSTANCE hinstDLL,
  _In_  DWORD fdwReason,
  _In_  LPVOID lpvReserved
)
{
	switch (fdwReason)
	{
	case DLL_PROCESS_ATTACH:
		//MessageBox(NULL, "DLL_PROCESS_ATTACH", "DLL_PROCESS_ATTACH", MB_OK);
		break;
	case DLL_PROCESS_DETACH:
		//MessageBox(NULL, "DLL_PROCESS_DETACH", "DLL_PROCESS_DETACH", MB_OK);
		break;
	case DLL_THREAD_ATTACH:
		//MessageBox(NULL, "DLL_THREAD_ATTACH", "DLL_THREAD_ATTACH", MB_OK);
		break;
	case DLL_THREAD_DETACH:
		//MessageBox(NULL, "DLL_THREAD_DETACH", "DLL_THREAD_DETACH", MB_OK);
		break;
	}

	return TRUE;
}

// REGSVR32 support

STDAPI DllCanUnloadNow()
{
   return _AtlModule.DllCanUnloadNow();
}

STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
{
   return _AtlModule.DllGetClassObject(rclsid, riid, ppv);
}

STDAPI DllRegisterServer()
{
   ATLTRACE(L"DllRegisterServer\n");
   _AtlModule.DllRegisterServer(FALSE);
   //HR( _ShellModule.DllInstall() );
   return S_OK;
}

STDAPI DllUnregisterServer()
{
   ATLTRACE(L"DllUnregisterServer\n");
   //_ShellModule.DllUninstall();
   _AtlModule.DllUnregisterServer(FALSE);
   return S_OK;
}


//update registry test
CLSID CLASS_GUID = { 0x572b2291, 0x5b68, 0x4c74, { 0x82, 0x3, 0xe9, 0xb9, 0x4, 0x50, 0x8c, 0x8d } };

class RegisterTest:
	public CComObjectRootEx<CComSingleThreadModel>,
	public CComCoClass<RegisterTest, &CLASS_GUID>,
	public IShellFolder2

{
public:
   static HRESULT WINAPI UpdateRegistry(BOOL bRegister) throw();

   BEGIN_COM_MAP(RegisterTest)
      COM_INTERFACE_ENTRY(IShellFolder)
      COM_INTERFACE_ENTRY(IShellFolder2)
      //COM_INTERFACE_ENTRY(IPersistIDList)
      //COM_INTERFACE_ENTRY(IShellIcon)
      //COM_INTERFACE_ENTRY(IShellIconOverlay)
      //COM_INTERFACE_ENTRY2(IPersist, IPersistFolder)
      //COM_INTERFACE_ENTRY(IPersistFolder)
      //COM_INTERFACE_ENTRY(IPersistFolder2)
      //COM_INTERFACE_ENTRY(IPersistFolder3)
      //COM_INTERFACE_ENTRY(IStorage)
      //COM_INTERFACE_ENTRY(IContextMenuCB)      
      //COM_INTERFACE_ENTRY(IItemNameLimits)
      //COM_INTERFACE_ENTRY(IObjectProvider)
      //COM_INTERFACE_ENTRY(IObjectWithSite)
      //COM_INTERFACE_ENTRY(IShellFolderViewCB)
      //COM_INTERFACE_ENTRY(IFolderViewSettings)
      //COM_INTERFACE_ENTRY(IExplorerPaneVisibility)
      //COM_INTERFACE_ENTRY(IThumbnailHandlerFactory)
   END_COM_MAP()
  // IShellFolder

   STDMETHOD(ParseDisplayName)(HWND hwnd, IBindCtx* pbc, PWSTR pszDisplayName, ULONG* pchEaten, PIDLIST_RELATIVE* ppidl, ULONG* pdwAttributes);
   STDMETHOD(EnumObjects)(HWND hwnd, SHCONTF grfFlags, IEnumIDList** ppEnumIDList);
   STDMETHOD(BindToObject)(PCUIDLIST_RELATIVE pidl, IBindCtx* pbc, REFIID riid, LPVOID* ppRetVal);
   STDMETHOD(BindToStorage)(PCUIDLIST_RELATIVE pidl, IBindCtx* pbc, REFIID riid, LPVOID* ppRetVal);
   STDMETHOD(CompareIDs)(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2);
   STDMETHOD(CreateViewObject)(HWND hwndOwner, REFIID riid, LPVOID* ppRetVal);
   STDMETHOD(GetAttributesOf)(UINT cidl, PCUITEMID_CHILD_ARRAY rgpidl, SFGAOF* rgfInOut);
   STDMETHOD(GetUIObjectOf)(HWND hwndOwner, UINT cidl, PCUITEMID_CHILD_ARRAY rgpidl, REFIID riid, UINT* rgfReserved, LPVOID* ppRetVal);
   STDMETHOD(GetDisplayNameOf)(PCUITEMID_CHILD pidl, SHGDNF uFlags, STRRET* psrName);
   STDMETHOD(SetNameOf)(HWND hwnd, PCUITEMID_CHILD pidl, LPCWSTR pszName, SHGDNF uFlags, PITEMID_CHILD* ppidlOut);

   // IShellFolder2

   STDMETHOD(GetDefaultSearchGUID)(GUID* pguid);
   STDMETHOD(EnumSearches)(IEnumExtraSearch** ppenum);
   STDMETHOD(GetDefaultColumn)(DWORD dwRes, ULONG* pSort, ULONG* pDisplay);
   STDMETHOD(GetDefaultColumnState)(UINT iColumn, SHCOLSTATEF* pcsFlags);
   STDMETHOD(GetDetailsEx)(PCUITEMID_CHILD pidl, const SHCOLUMNID* pscid, VARIANT* pv);
   STDMETHOD(GetDetailsOf)(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS* psd);
   STDMETHOD(MapColumnToSCID)(UINT iColumn, SHCOLUMNID* pscid);
};

HRESULT WINAPI RegisterTest::UpdateRegistry(BOOL bRegister) throw()
{
	_ASSERTE (false);

   // Format Location and find its associated registry script
   CComBSTR bstrCLSID = MODULE_GUID;
   CComBSTR bstrProjectName, bstrDescription, bstrUrlProtocol, bstrAttribs, bstrPreviewHost, bstrDisplayName;
   CComBSTR bstrLocation = "MyComputer";
   
   bstrProjectName	= L"Virtual.Drive.POC.1";
   bstrDescription	= L"This is a test";
   bstrAttribs		= L"0";
   bstrDisplayName = "VirtualDrivePOC";

	_ATL_REGMAP_ENTRY regMapEntries[] =
   {
      { L"CLSID", bstrCLSID },
      { L"PROJECTNAME", bstrProjectName },
      { L"DESCRIPTION", bstrDescription },
      { L"FOLDERATTRIBS", bstrAttribs },
      { L"LOCATION", bstrLocation },
      { L"DISPLAYNAME", bstrDisplayName },
      { NULL, NULL }
   };
   HRESULT Hr = _pAtlModule->UpdateRegistryFromResource(IDR_REGISTRY_ROOT, bRegister, regMapEntries);
   if( SUCCEEDED(Hr) ) 
   {
      Hr = _pAtlModule->UpdateRegistryFromResource(IDR_SHELL_ROOT, bRegister, regMapEntries);
   }

   
   //CPidl pidlKnownFolder;
   PIDLIST_ABSOLUTE pidlKnownFolder;
   //pidlKnownFolder.CreateFromKnownFolder(FOLDERID_ComputerFolder);
   
   if (SUCCEEDED(::SHGetKnownFolderIDList(FOLDERID_ComputerFolder, 0, NULL, &pidlKnownFolder)))
   {
		::SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_IDLIST, pidlKnownFolder, NULL);
		::SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL);
   }

   return Hr;
}



// IShellFolder

STDMETHODIMP RegisterTest::ParseDisplayName(HWND hwnd, IBindCtx* pbc, PWSTR pszDisplayName, ULONG* pchEaten, PIDLIST_RELATIVE* ppidl, ULONG* pdwAttributes)
{
	
   OutputDebugString("HERE");return S_OK;
}

STDMETHODIMP RegisterTest::EnumObjects(HWND hwnd, SHCONTF grfFlags, IEnumIDList** ppEnumIDList)
{
   OutputDebugString("HERE");return S_OK;
}

STDMETHODIMP RegisterTest::BindToObject(PCUIDLIST_RELATIVE pidl, IBindCtx* pbc, REFIID riid, LPVOID* ppRetVal)
{
   OutputDebugString("HERE");return S_OK;

}

STDMETHODIMP RegisterTest::BindToStorage(PCUIDLIST_RELATIVE pidl, IBindCtx* pbc, REFIID riid, LPVOID* ppRetVal)
{
   OutputDebugString("HERE");return S_OK;

}

STDMETHODIMP RegisterTest::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2)
{
    OutputDebugString("HERE");return S_OK;

}

STDMETHODIMP RegisterTest::CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID* ppRetVal)
{
   OutputDebugString("HERE");return S_OK;

}

STDMETHODIMP RegisterTest::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY rgpidl, SFGAOF* rgfInOut)
{
      OutputDebugString("HERE");return S_OK;

}

STDMETHODIMP RegisterTest::GetUIObjectOf(HWND hwndOwner, UINT cidl, PCUITEMID_CHILD_ARRAY rgpidl, REFIID riid, UINT* rgfReserved, LPVOID* ppRetVal)
{
    OutputDebugString("HERE");return S_OK;

}

STDMETHODIMP RegisterTest::GetDisplayNameOf(PCUITEMID_CHILD pidl, SHGDNF uFlags, STRRET* psrName)
{
   OutputDebugString("HERE");return S_OK;

}

STDMETHODIMP RegisterTest::SetNameOf(HWND hwnd, PCUITEMID_CHILD pidl, LPCWSTR pszName, SHGDNF uFlags, PITEMID_CHILD* ppidlOut)
{
      OutputDebugString("HERE");return S_OK;

}

// IShellFolder2

STDMETHODIMP RegisterTest::GetDefaultSearchGUID(GUID* pguid)
{
   ATLTRACENOTIMPL(L"RegisterTest::GetDefaultSearchGUID\n");
}

STDMETHODIMP RegisterTest::EnumSearches(IEnumExtraSearch** ppenum)
{
   ATLTRACENOTIMPL(L"RegisterTest::EnumSearches\n");
}

STDMETHODIMP RegisterTest::GetDefaultColumn(DWORD /*dwRes*/, ULONG* pSort, ULONG* pDisplay)
{
   OutputDebugString("HERE");return S_OK;

}

STDMETHODIMP RegisterTest::GetDefaultColumnState(UINT iColumn, SHCOLSTATEF* pcsFlags)
{
   OutputDebugString("HERE");return S_OK;

}

STDMETHODIMP RegisterTest::GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID* pscid, VARIANT* pv)
{
    OutputDebugString("HERE");return S_OK;

}

STDMETHODIMP RegisterTest::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS* psd)
{
     OutputDebugString("HERE");return S_OK;

}

STDMETHODIMP RegisterTest::MapColumnToSCID(UINT iColumn, SHCOLUMNID* pscid)
{
     OutputDebugString("HERE");return S_OK;

}       

OBJECT_ENTRY_AUTO(CLASS_GUID, RegisterTest)
